#include <windows.h>
#include <wincrypt.h>
#include "crypto.h"

CMyCrypto::CMyCrypto(LPTSTR pszPassword, ALG_ID algorithm)
{
	m_hasConstructorError = FALSE;
	m_hProv = NULL;
	m_hKey = NULL;

	//Get handle to the default key container in default CSP
	if (CryptAcquireContext(&m_hProv, // handle to the CSP
							NULL, // default container
							MS_DEF_PROV, //default CSP
							PROV_RSA_FULL, // provider type
							CRYPT_VERIFYCONTEXT)) { //action
		HCRYPTHASH hHash;
		//Get handle to the hash object
		if (CryptCreateHash(m_hProv, // handle to the CSP
							CALG_MD5, // hashing algorithm
							0, //non-keyed hash
							0, //reserved, must be 0
							&hHash)) {
			//Hash the password
			if (CryptHashData(hHash, // handle to the hash object
							(LPBYTE)pszPassword, // data buffer
							lstrlen(pszPassword)*sizeof(TCHAR),
							0)) { // flags
				// Create the session key using the hashed password
				if (!CryptDeriveKey(m_hProv, //handle to CSP
							algorithm, //encryption algorithm
							hHash, //hashed data
							CRYPT_EXPORTABLE | 0x00280000,
							&m_hKey)) { // session key
					m_hasConstructorError = TRUE;
				}
			}
			else
			{
				m_hasConstructorError = TRUE;
			}
			if (!CryptDestroyHash(hHash))
			{
				m_hasConstructorError = TRUE;
			}
		}
		else
		{
			m_hasConstructorError = TRUE;
		}
	}
	else
	{
		m_hasConstructorError = TRUE;
	}
}

CMyCrypto::~CMyCrypto()
{
	if (m_hKey != NULL) {
		CryptDestroyKey(m_hKey);
	}
	if (m_hProv != NULL) {
		CryptReleaseContext(m_hProv, 0);
	}
}

BOOL CMyCrypto::Encrypt(LPBYTE pData, LPDWORD pdwDataSize,
						DWORD dwBufferSize, BOOL bFinal)
{
	return CryptEncrypt(m_hKey, //encryption key handle
						0, //optional hash handle
						bFinal, //true if last block
						0, //flag (reserved)
						pData, //data to encrypt
						pdwDataSize, //data size in bytes
						dwBufferSize); //buffer size in bytes
}

BOOL CMyCrypto::Decrypt(LPBYTE pData, LPDWORD pdwDataSize,
						BOOL bFinal)
{
	return CryptDecrypt(m_hKey, //encryption key handle
						0, // optional hash handle
						bFinal, //true if last block
						0, //flag (reserved)
						pData, //data to encrypt
						pdwDataSize); //data size (in bytes)
}

BOOL CMyCrypto::HasConstructorError()
{
	return m_hasConstructorError;
}